package com.hxk.juc.collection;

import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * 多线程情况下list案例
 */
public class ManyThreadListCase {

    public static void main(String[] args) {
        //singleThread();
        //manyThreadNotSafe();
        //manyThreadSafe1();
        //manyThreadSafe2();
        manyThreadSafe3();
    }

    /**
     * 在单线程情况下ArrayList没有问题
     */
    public static void singleThread(){
        //底层是一个object[]数组，默认初始长度为10，动态扩容10的一半，扩容后使用Array.copyOf将老数据复制到扩容后的数据中
        List<String> list = new ArrayList<>();
        //在add的时候才会判断初始大小
        //单线程情况下，没有问题
        list.add("a");
        list.add("b");
        list.add("c");
        list.add("d");
        list.forEach(System.out::println);
    }

    /**
     * 在多线程情况下ArrayList是线程不安全
     *      会出现ConcurrentModificationException
     */
    public static void manyThreadNotSafe(){
        List<String> list = new ArrayList<>();
        for (int i = 1; i <= 30; i ++){
            new Thread(()->{
                list.add(UUID.randomUUID().toString().substring(0,8));
                System.out.println(Thread.currentThread().getName()+"\t"+list);
            },"00"+i).start();
        }
    }

    /**
     * 处理多线程下ArrayList线程不安全方式1：
     * 使用ArrayList对应的线程安全集合类Vector
     *      在Vector中的add方法加了synchronized对象锁在add时候锁住整个Vector对象
     */
    public static void  manyThreadSafe1(){
        List<String> list = new Vector<>();
        for (int i = 0; i < 30; i++) {
            new Thread(()->{
                list.add(UUID.randomUUID().toString().substring(0,8));
                System.out.println(Thread.currentThread().getName()+"\t"+list);
            },String.valueOf(i)).start();
        }
    }

    /**
     *处理多线程下ArrayList线程不安全方式2：
     * 使用集合工具类Collections提供的Collections.synchronizedList(new ArrayList<>())方法获取线程安全的ArrayList
     *      使用Collections.synchronizedList(new ArrayList<>())方法获取的ArrayList，
     *      在添加时方法内部使用synchronized(mutex)锁住了一个Object mutex对象
     *      在这里锁的颗粒度变小了，锁的不是整个对象。从性能上优于上面的方法
     */
    public static void manyThreadSafe2(){
        List<String> list = Collections.synchronizedList(new ArrayList<>());
        for (int i = 0; i < 30; i++) {
            new Thread(()->{
                list.add(UUID.randomUUID().toString().substring(0,8));
                System.out.println(Thread.currentThread().getName()+"\t"+list);
            },String.valueOf(i)).start();
        }
    }
    /**
     *处理多线程下ArrayList线程不安全方式3：
     * 使用jdk1.5后新加入的juc中的CopyOnWriteArrayList线程安全类
     *      在CopyOnWriteArrayList中的add方法使用了juc中的ReentrantLock（重入锁），
     *      让锁的颗粒度变得更小，目前是性能上最优的解决方案
     */
    public static void manyThreadSafe3(){
        List<String> list = new CopyOnWriteArrayList();
        for (int i = 0; i < 30; i++) {
            new Thread(()->{
                list.add(UUID.randomUUID().toString().substring(0,8));
                System.out.println(Thread.currentThread().getName()+"\t"+list);
            },String.valueOf(i)).start();
        }
    }


}

